package com.tjhk.java.tech;

import java.lang.ref.*;

/**
 * (一) 强引用(StrongReference)
 * 在一个线程内，无须引用直接可以使用的对象，强引用不会被JVM清理。我们平时申明变量使用的就是强引用，普通系统99%以上都是强引 用，比如，String s=＂Hello World＂。
 *
 * Java中的引用，有点像 C++的指针。通过引用，可以对堆中的对象进行操作。在Java 程序中，最常见的引用类型是强引用，它也是默认的引用类型。例如：StringBuffer str=new StringBuffer（“Hello World”）；
 * 当在Java语言中使用new 操作符创建一个新的对象，并将其赋值给一个变量的时候，这个变量就成为指向该对象的一个强引用。而判断一个对象是否存活的标准为是否存在指向这个对象的引用。
 *
 * 强引用具备以下特点：
 * （1）强引用可以直接访问目标对象。
 * （2）强引用所指向的对象在任何时候都不会被系统回收。JVM宁愿抛出Out Of Memory异常也不会回收强引用所指向的对象。
 * （3）强引用可能导致内存泄漏。
 *
 * 通常来说，应用程序内部的内存泄露有两种情况。一种是虚拟机中存在程序无法使用的内存区域,另一种情况是程序中存在大量存活时间过长的对象。
 *
 * (二) 软引用(SoftReference)
 * java中使用SoftRefence来表示软引用
 *
 * 软引用是除了强引用外最强的引用类型，我们可以通过java.lang.ref.SoftReference使用软引用。一个持有软引用的对象，它不会被JVM很快回收，JVM会根据当前堆的使用情况来判断何时回收。当堆使用率临近阙值时，才会去回收软引用的对象。只要有足够的内 存，软引用便可能在内存中存活相当长一段时间。通过软引用，垃圾回收器就可以在内存不足时释放软引用可达的对象所占的内存空间。保证程序正常工作。
 *
 * 通过一个软引用申明，JVM抛出OOM之前，清理所有的软引用对象。垃圾回收器某个时刻决定回收软可达的对象的时候，会清理软引用，并可选的把引用存放到一个引用队列（ReferenceQueue）。
 *
 * (三) 弱引用(WeakReference)
 * java中使用WeakReference来表示弱引用。如果某个对象与弱引用关联，那么当JVM在进行垃圾回收时，无论内存是否充足，都会回收此类对象。
 *
 * 通过一个弱引用申明。类似弱引用，只不过 Java 虚拟机会尽量让软引用的存活时间长一些，迫不得已才清理。
 *
 * (四) 虚引用(PhantomReference)
 * java中使用PhantomReference来表示虚引用。
 *
 * 通过一个虚引用申明。仅用来处理资源的清理问题，比Object里面的finalize机制更灵活。get方法返回的永远是null，Java虚拟机不负责清理虚引用，但是它会把虚引用放到引用队列里面。
 *
 * 虚引用的主要目的是在一个对象所占的内存被实际回收之前得到通知，从而可以进行一些相关的清理工作。弱引用之前的两种引用类型有很大的不同：首先虚引用在创建时必须提供一个引用队列作为参数；其次虚引用对象的get方法总是返回null，因此无法通过虚引用来获取被引用的对象。
 */
public class ReferenceTest {
    static  class Student{
        private String name;

        public Student(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }

    static class Entry {
        private Student referent;
        String value;
        public Entry(Student referent,String v) {
            this.referent = referent;
            value = v;
        }
        public Student getReferent(){
            return this.referent;
        }
    }

    static class Entry2 extends WeakReference<Student> {
        String value;
        public Entry2(Student referent,String v) {
            super(referent);
            value = v;
        }
        public Student getReferent(){
            return this.get();
        }
    }


    public static void main(String[] args) {
        String s = "引用测试";
        // 软引用
        SoftReference softReference = new SoftReference("软引用");
        System.out.println(">>>>>>"+softReference.get());
        System.gc();;
        System.out.println("回收后："+softReference.get());

        // 弱引用
        WeakReference weakReference = new WeakReference("弱引用");
        System.out.println(">>>>>>"+weakReference.get());
        System.gc();;
        System.out.println("回收后："+weakReference.get());

        // 虚引用
        ReferenceQueue<Object> queue = new ReferenceQueue<>();
        PhantomReference<String> phantomReference = new PhantomReference<>("虚引用",queue);
        System.out.println(phantomReference.get());

        // 强引用
        Entry[] table = new Entry[16];
        Student student = new Student("张三");
        table[0] = new Entry(student,"张三");
        student = new Student("李四");
        System.out.println("强引用回收前："+table[0].getReferent());
        System.gc();
        // 垃圾回收后referent 为空
        System.out.println("强引用回收后："+table[0].getReferent());

        // 弱引用
        Entry2[] table2 = new Entry2[16];
        Student student2 = new Student("张三");
        table2[0] = new Entry2(student2,"张三");
        student2 = new Student("李四");
        System.out.println("弱引用回收前："+table2[0].getReferent());
        System.gc();
        // 垃圾回收后referent 为空
        System.out.println("弱引用回收后："+table2[0].getReferent());

    }
}
